Thread: [C] Debuger

  1. #1
    Registered User
    Join Date
    Jul 2009
    Location
    Croatia
    Posts
    272

    [C] Debuger

    So im writing the C Programming Language, 2nd edition 1-24 exercise. I'm done with the states part of the programm.

    The problem is, i dont know how to implement the function to check for the braces, parantheses and brackets errors.

    Do i need a global array, or how can i get it done? I sure don't want to have the same code in 2 places in my code.

    I asked on another forum, but they insist on making pointers, and push/pop functions. But i haven't worked with them yet, so i don't know how.

    If anyone is willing to do it that way, just to fix it with pointers, it's fine with me aswell.

    "Write a program to check a C program for rudimentary syntax errors
    like unbalanced parentheses, brackets and braces. Don't forget about quotes,
    both single and double, escape sequences, and comments. (This program is hard if you do it in full generality.)"


    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    void checker(char c, int x);
    
    
    
    int main(int argc, char *argv[])
    {
         
         
         enum states {normal,                               /* normal */
                      comment, comment_entry, comment_exit, /* comment stanja */
                      dquote, dquote_escape,                /* " navodnici */
                      squote, squote2, squote_escape};      /* ' konstante */
                      
         int state = normal;
         int c=0;
         
         
                while ((c = getchar()) != EOF)
                {
                 
                 if (state == normal && c == '/') { state = comment_entry; }
                 else if(state==normal && c=='"') { state = dquote; }
                 else if(state==normal && c=='\'') { state = squote; }
                 
                 else if (state == normal) { checker(c, x);}
    
                 else if (state == comment && c != '*') { continue; }
                 else if (state == comment) { state = comment_exit; continue; }
       
                 else if (state == comment_exit && c == '/') { state = normal; continue; }
                 else if (state == comment_exit && c == '*') { continue; }
                 else if (state == comment_exit) { state = comment; continue; }
       
                 else if (state == comment_entry && c == '*') { state = comment; continue; }
                 else if (state == comment_entry && c == '/') { }
                 else if (state == comment_entry) { state = normal; checker(c, x); }
                 
                 else if(state==dquote && c=='"') { state = normal; }
                 else if(state==dquote && c=='\\') { state = dquote_escape; }
                 else if(state==dquote_escape) { state=dquote; continue; }
                 
                 else if(state==squote && c=='\\') { state= squote_escape; }
                 else if(state==squote && c=='\'') { printf("Line %d: Constant error '' "); }
                 else if(state==squote && c!='\'' && c!='\\') { state=squote2; }
                 else if(state==squote_escape) { state= squote2; }
                 else if(state==squote2 && c=='\'') { state=normal; }
                 else if(state==squote2 && c!='\'') {printf("Line %d: Constant too long!"); }
                 
                }
                 
       
              
      
      
      getchar();
      return 0;
    }
    Last edited by Tool; 11-12-2009 at 09:51 AM.

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    You might consider nesting some of the constructs, so for example:
    Code:
    else if (state == comment_exit && c == '/') { state = normal; continue; }
    else if (state == comment_exit && c == '*') { continue; }
    else if (state == comment_exit) { state = comment; continue; }
    could be
    Code:
    else if (state == comment_exit) {
          switch (c) {
                case ('/'): state = normal; break;
                case ('*'): break;
                default: state = comment;
           }
    }
    You could use more if/elses instead of the switch/case. You do not need all those "continue" statements this way, as the flow of execution means the top level "choice" is based on a single variable (state).

    This is also slightly more optimal, I think, because it saves having to repeatedly check for the same condition.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    Jul 2009
    Location
    Croatia
    Posts
    272
    Thanks for the tip. I wrote continue cause it seems more clear to me(easier to read).

    But that wasn't my main question.

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Tool View Post
    The problem is, i dont know how to implement the function to check for the braces, parantheses and brackets errors.
    In a the same way you are already doing, using "state" (your enum will need some more states). Actually, you will need an integer flag for each style of bracket to set when the bracket opens, since they can be nested. For something like this:
    Code:
    int x = pow((x+4*(n-2))/100);
    The flag for () starts at 0 and increments by one (++) for each ( and decrements (--) for each ).

    There is a problem with your method that will complicate all this. It is a little bit too "low level" in the way you break a comment down /* and //. What you should really do is read the entire file into a char array -- that means you need to stat the file first to get the length. Either you can learn how to do that now, with fstat(), or you can wait til later and for now just open and read it twice (once to count the length, then to read it into an array). The size of the array is set with malloc().

    Once the file is in an array, you can use a "lookahead" character. That is, if you loop thru the array:
    Code:
    for (i=0; i<file_length; i++) {
    The "lookahead" character will be i+1. So if i is '/', then the lookahead determines whether you are in a multi-line comment ('*') or a single line comment ('/'). The multi-line comment state terminates with */ whereas the single line terminates with a /n. This will reduce your number of enumerated states since you won't have to fiddle with comment_entry and comment_exit.

    Or you may be able to get a way without doing that, just IMO parsing is easier this way (reading the file into memory first).
    Last edited by MK27; 11-12-2009 at 10:54 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Registered User
    Join Date
    Jul 2009
    Location
    Croatia
    Posts
    272
    I allready wrote that version of the program, in which the characters get entered into an array.

    The problem with that method is that i cannot track the line in which i am when the error occurs. All i can do is count numbers of errors, which is useless. I want to be able to know in which line i am, and then write the corresponding error if it happens. "Line x: Error."

    Thats why i switched to this way, and this method seems much easier cause i can actually draw it on a paper (states).


    But i think i have an idea.

    Before the states part of the code, i could add:

    Code:
    if(state==normal || state==comment_entry)
    {
        /*adding to the stack if braces, parantheses or brackets and performing check*/
    }
    Would that work?
    Last edited by Tool; 11-12-2009 at 11:14 AM.

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Tool View Post
    The problem with that method is that i cannot track the line in which i am when the error occurs. All i can do is count numbers of errors, which is useless.


    Hey Tool:
    Code:
    int line_num = 1;
    if (c == '\n') line_num++;
    If you have already done it/can do it using the array, I really really strongly that that is what you do. That is how your compiler works, for example -- it does not just read once thru one character at a time. It loads your code into memory and contains it in data structures and parses it using a "lookahead" (among other things) which I didn't just make that idea up.

    I know re-writing code again seems like a drag but that's programming. No point in sticking to something purely out of laziness! That is what I am doing today, re-writing parts of a search engine I wrote before, based on some experiments that convinced me it could be done better.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    Registered User
    Join Date
    Jul 2009
    Location
    Croatia
    Posts
    272
    Yeah, i agree, reading it into array makes it alot easier (less code). So here it is:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #define STACK_MAX 100
    #define MAX_SIZE 1000
    
    int Brackets(char c);  
    int Push(char c);    
    char Pop();
    
    char Stack[STACK_MAX];
    int StackTop = -1;
    
    int main(int argc, char *argv[])
    {
         
         enum { normal,
                dquote,
                squote, squote2,
                comment };
                
         int c;
         int x=0;
         int pom=0;
         int line=1;
         int array[MAX_SIZE];
         int state=normal;
         char tmp=0;
         
          while((c=getchar())!=EOF && x<MAX_SIZE)
          array[x++]=c;
          
          array[x]='\n';
          x++;
          array[x]='\0';
          
          pom=x;
          
          for(x=0; x<pom; x++)
          {
              if(array[x]=='\n') 
              line++;
              
              if(array[x]=='/' && array[x+1]=='*' && state==normal) { state = comment; }
              else if(array[x]=='*' && array[x+1]=='/' && state==comment) { state = normal; }
    
              else if(array[x]=='"' && state==normal) { state = dquote; }
              else if(array[x]=='"' && array[x-1]!='\\' && state==dquote) { state = normal; }
    
              else if(array[x]=='\'' && state==normal) { state=squote; }
              else if(state==squote && array[x]=='\\') { state= squote_escape; }
              else if(state==squote && array[x]=='\'') { printf("Line %d: Constant error '' \n", line); state=normal; }
              else if(state==squote && array[x]!='\'' && array[x]!='\\') { state=squote2; }
              else if(state==squote_escape) { state= squote2; }
              else if(state==squote2 && array[x]=='\'') { state=normal; }
              else if(state==squote2 && array[x]!='\'') {printf("Line %d: Constant too long!\n", line); state=squote3; }
              else if(state==squote3 && array[x]=='\'') { state=normal; }
              
              if(state==normal)
              if((tmp=Brackets(array[x]))==0) printf("Line %d: Mismatching %c\n", line, array[x]);
          }     
          
          for(x=0; x<=StackTop; x++)
          printf("Mismatching %c.\n", Stack[x]);
         
          switch(state)
          {
            case comment: printf("Code ends inside a comment."); break;
            case dquote: printf("Code ends inside \"."); break;
            case squote: printf("Code ends inside '"); break;
          }
          
          
          
          printf("\nPress any key to continue.");
          getchar();    
          return 0;
          
    }
    
    int Brackets(char c)
    {
       char tmp;
    
       switch (c)
       {
          case '(':
          case '[':
          case '{':
             if (Push(c) == 0) return 0;
             break;
          case ')':
             tmp = Pop();
             if (tmp == -1) return 0;
             if (tmp != '(') return 0;
             break;
          case ']':
             tmp = Pop();
             if (tmp == -1) return 0;
             if (tmp != '[') return 0;
             break;
          case '}':
             tmp = Pop();
             if (tmp == -1) return 0;
             if (tmp != '{') return 0;
             break;
       }
       
       return 1;
    }
    
    int Push(char c)
    {
       if (StackTop == STACK_MAX) return 0;
       if (++StackTop < 0) return 0; 
       
       Stack[StackTop] = c;
       
       
       return 1;
    }
    
    char Pop()
    {
       if (StackTop < 0) return -1;
       return Stack[StackTop--];
    }

    Any feedback is appreciated. I think i could say i'm done with this exercise now , but i'd like your opinion aswell if i can improve it somehow.
    Last edited by Tool; 11-12-2009 at 06:11 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. [C#] MySQl database problems
    By Jelte in forum C# Programming
    Replies: 5
    Last Post: 09-26-2008, 03:11 AM
  2. [C#] ducumentation About AES(Rijndael)
    By Jelte in forum C# Programming
    Replies: 1
    Last Post: 09-22-2008, 08:31 AM
  3. [C] Drag and drop controls
    By pc2-brazil in forum Windows Programming
    Replies: 1
    Last Post: 09-02-2008, 02:41 AM
  4. [C#] howto compare combobox-item with DataSet
    By Jelte in forum C# Programming
    Replies: 3
    Last Post: 08-26-2008, 06:25 PM
  5. [C#] Validation class for events?
    By gicio in forum C# Programming
    Replies: 4
    Last Post: 01-03-2003, 12:19 PM